package io.grpc.examples.helloworldtls;

import java.io.File;
import java.security.PrivateKey;
import java.security.cert.X509Certificate;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.net.ssl.SSLException;

import org.apache.commons.io.FileUtils;

import com.asgard.crypto.CryptoService;
import com.asgard.crypto.ECKey;
import com.asgard.keybox.KeyBox;
import com.asgard.utils.CertificateUtils;
import com.asgard.utils.CryptoUtils;

import io.grpc.ManagedChannel;
import io.grpc.StatusRuntimeException;
import io.grpc.examples.helloworld.GreeterGrpc;
import io.grpc.examples.helloworld.HelloReply;
import io.grpc.examples.helloworld.HelloRequest;
import io.grpc.examples.helloworldtls.trust.MyTrustManagerFactory;
import io.grpc.netty.GrpcSslContexts;
import io.grpc.netty.NegotiationType;
import io.grpc.netty.NettyChannelBuilder;
import io.netty.handler.ssl.SslContext;
import io.netty.handler.ssl.SslContextBuilder;

public class BCHelloWorldClientTls {
	private static final Logger logger = Logger.getLogger(BCHelloWorldClientTls.class.getName());

	private final ManagedChannel channel;
	private final GreeterGrpc.GreeterBlockingStub blockingStub;

	static SslContext buildSslContext(String trustCertCollectionFilePath, String clientCertChainFilePath,
			String clientPrivateKeyFilePath) throws SSLException {
		SslContextBuilder builder = GrpcSslContexts.forClient();
		if (trustCertCollectionFilePath != null) {
			builder.trustManager(new File(trustCertCollectionFilePath));
		}
		if (clientCertChainFilePath != null && clientPrivateKeyFilePath != null) {
			builder.keyManager(new File(clientCertChainFilePath), new File(clientPrivateKeyFilePath));
		}
		return builder.build();
	}
//        SslContextBuilder sslContextBuilder = SslContextBuilder.forClient()
//                .keyManager(privateKey, keyCertChain)
//                .trustManager(keyCertChain)
//                .trustManager(new MyTrustManagerFactory(""));
//        SslContext sslContext = GrpcSslContexts.configure(sslContextBuilder, SslProvider.OPENSSL)
//                .build();
//        channel = NettyChannelBuilder.forAddress(ip, port).sslContext(sslContext)
//                .maxInboundMessageSize(GlobalConfig.maxNetworkMessageSize).build();
//        stub = PeerServiceGrpc.newStub(channel);

	static SslContext buildSslContext(String keyboxPath) throws Exception {
		File keyBoxFile = new File(keyboxPath);
		KeyBox keyBox = new KeyBox();
		keyBox.loadFromFile(keyBoxFile, "PASSWORD");
		ECKey eckey = keyBox.getKey("ECKey");
		PrivateKey privateKey = eckey.getPrivateKey();
		X509Certificate x509Certificate = keyBox.getCertificate("ENROLL_CERT").getX509Cert();

		SslContextBuilder builder = GrpcSslContexts.forClient();
		builder.trustManager(new MyTrustManagerFactory(""));
		builder.keyManager(privateKey, x509Certificate);

//        X509Certificate cert = CertificateUtils
//                .decode(FileUtils.readFileToString(new File("C:\\Users\\taifu\\Desktop\\临时\\grpc-cert\\client.crt")));
//        X509Certificate cacert = CertificateUtils
//                .decode(FileUtils.readFileToString(new File("C:\\Users\\taifu\\Desktop\\临时\\grpc-cert\\ca.crt")));
//        PrivateKey key = CryptoUtils.getPrivateKey(
//                FileUtils.readFileToString(new File("C:\\Users\\taifu\\Desktop\\临时\\grpc-cert\\client.key")));
//        SslContextBuilder builder = GrpcSslContexts.forClient();
//        builder.trustManager(new MyTrustManagerFactory(""));
//        builder.keyManager(key, cert);

		return builder.build();
	}

	static SslContext buildGMSslContext(String keyboxPath) throws Exception {
		File keyBoxFile = new File(keyboxPath);
		KeyBox keyBox = new KeyBox();
		keyBox.loadFromFile(keyBoxFile, "PASSWORD");
		ECKey eckey = keyBox.getKey("ECKey");
		PrivateKey privateKey = eckey.getPrivateKey();
		X509Certificate x509Certificate = keyBox.getCertificate("ENROLL_CERT").getX509Cert();

		X509Certificate cert = CertificateUtils
				.decode(FileUtils.readFileToString(new File("C:\\Users\\taifu\\Desktop\\临时\\grpc-cert\\client.crt")));
		X509Certificate cacert = CertificateUtils
				.decode(FileUtils.readFileToString(new File("C:\\Users\\taifu\\Desktop\\临时\\grpc-cert\\ca.crt")));
		PrivateKey key = CryptoUtils.getPrivateKey(
				FileUtils.readFileToString(new File("C:\\Users\\taifu\\Desktop\\临时\\grpc-cert\\client.key")));

		SslContextBuilder builder = GrpcSslContexts.forClient().trustManager(cert)
				.trustManager(new MyTrustManagerFactory("")).keyManager(key, cert);
		return builder.build();

//        return SMSslClientContextFactory.build(
//                getGmCaCert().getInputStream(),
//                getGmEnSslCert().getInputStream(),
//                getGmEnSslKey().getInputStream(),
//                getGmSslCert().getInputStream(),
//                getGmSslKey().getInputStream());
	}

	public BCHelloWorldClientTls(String host, int port, SslContext sslContext) throws SSLException {

		this(NettyChannelBuilder.forAddress(host, port).negotiationType(NegotiationType.TLS).sslContext(sslContext)
				.build());
	}

	BCHelloWorldClientTls(ManagedChannel channel) {
		this.channel = channel;
		blockingStub = GreeterGrpc.newBlockingStub(channel);
	}

	public void shutdown() throws InterruptedException {
		channel.shutdown().awaitTermination(5, TimeUnit.SECONDS);
	}

	public void greet(String name) {
		logger.info("Will try to greet " + name + " ...");
		HelloRequest request = HelloRequest.newBuilder().setName(name).build();
		HelloReply response;
		try {
			response = blockingStub.sayHello(request);
		} catch (StatusRuntimeException e) {
			logger.log(Level.WARNING, "RPC failed: {0}", e.getStatus());
			return;
		}
		logger.info("============get grpc msg==============");
		logger.info("Greeting: " + response.getMessage());
		logger.info("============get grpc msg==============");
	}

	public static void main(String[] args) throws Exception {
		CryptoService.setUseSM(false);
		String keyboxPath = "E:\\develop\\tomcat\\apache-tomcat-8.5.54-8203\\resources\\keybox.xml";

//        CryptoService.setUseSM(true);
//        String keyboxPath = "E:\\develop\\tomcat\\apache-tomcat-8.5.54-8203\\resources\\SMTrueSSL\\keybox.xml";

		BCHelloWorldClientTls client = new BCHelloWorldClientTls("localhost", 7443, buildSslContext(keyboxPath));
		try {
			String user = "world taifu";
			if (args.length > 0) {
				user = args[0]; /* Use the arg as the name to greet if provided */
			}
			client.greet(user);
		} finally {
			client.shutdown();
		}
	}
}